#if !defined(___HUF_C)
#define ___HUF_C
#include "std.h"


#define RRSS(rr,ss)               ((((N1)(rr))<<4)|((N1)(ss)))
#define BUFVAL(rs,vv)             ((((N4)(N1)(rs))<<16)|((N4)(N2)(vv)))
#define BUFVAL2(dd,rs,vv)         ((((N4)(N1)(dd))<<24)|BUFVAL(rs,vv))


I4 GetBit(tGetBit *r1)
{ if (!r1)
    ERR1("Error: GetBit: Param",-1l);
  // GetByte
  while (!r1->cnt)
  { int ii=fgetc(r1->f1);
    if (ii==-1)
      ERR1("Error: GetBit: EOF/1",*r1->nn);
    r1->bb=(N1)ii; r1->cnt=8; ++*r1->nn;
    // Escape
    if (r1->bb==0xFF)
    { ii=fgetc(r1->f1);
      if (ii==-1)
        ERR1("Error: GetBit: EOF/2",*r1->nn);
      ++*r1->nn;
      switch (ii)
      { case 0:
          break;
        case 0xD0:
        case 0xD1:
        case 0xD2:
        case 0xD3:
        case 0xD4:
        case 0xD5:
        case 0xD6:
        case 0xD7:
          r1->bb=0; r1->cnt=0;
          DEB1("R%c",ii-0xD0+'0');
          break;
        default:
          ERR2("Error: GetBit: Marker: 0x%02X",
          *r1->nn-2,(N2)(N1)ii);
      }
    }
  }
  // GetBit
  { N1 bb=r1->bb>>7;
    r1->bb<<=1; --r1->cnt;
    return ((I4)(N4)bb);
  }
}

I4 GetVal(tGetBit *r1,N1 bits)
{ N2 n1,n2=0;

  if (bits>16)
    ERR1("Error: GetVal: Param",-1l);
  for (n1=0;n1<bits;++n1)
  { I4 ii=GetBit(r1);
    if (ii==-1l) return (-1l);
    n2=(n2<<1)|(N2)ii;
  }
  // Extend (sign)
  if (bits)
  { n1=1<<(bits-1);
    if (n2<n1)
    { n1=-1<<bits;
      n2+=n1+1;
    }
  }

  return ((I4)(N4)n2);
}

I4 Decode(tGetBit *r1,tHtab *htab)
{ N2 n1,n2=0;

  if (!htab)
    ERR1("Error: Decode: Param",-1l);
  for (n1=0;n1<16;++n1)
  { I4 ii=GetBit(r1);
    if (ii==-1l) return (-1l);
    n2=(n2<<1)|(N2)ii;
    if (htab->hufmax[n1]==(N2)-1l) continue;
    if (n2<=htab->hufmax[n1]) break;
  }
  if (n1==16)
    ERR1("Error: Decode",*r1->nn);
  n2=htab->hufidx[n1]+n2-htab->hufmin[n1];
  return ((I4)(N4)htab->val[n2]);
}

I4 GetDC(tGetBit *r1,tHtab *htab,I2 *dc)
{ I4 ii;

  if (!dc)
    ERR1("Error: GetDC: Param",-1l);
  ii=Decode(r1,htab);
  if (ii==-1l) return (-1l);
  ii=GetVal(r1,(N1)ii);
  if (ii==-1l) return (-1l);
  *dc+=(I2)ii; return (0);
}

I4 GetAC(tGetBit *r1,tHtab *htab,I2 *ac)
{ N2 n1,n2;

  if (!ac)
    ERR1("Error: GetAC: Param",-1l);
  for (n1=0;n1<63;++n1) ac[n1]=0;
  for (n1=0;n1<63;++n1)
  { I4 ii=Decode(r1,htab);
    if (ii==-1l) return (-1l);
    if (!ii) break;
    if (ii==0xF0)
    { if (n1+16>63)
        ERR2("Error: GetAC[%u]: 0xF0(16)",
        *r1->nn,n1);
      n1+=15; continue;
    }
    n2=((N2)ii)>>4;
    if (n1+n2>63)
      ERR3("Error: GetAC[%u]: RR(%u)",
      *r1->nn,n1,n2);
    n1+=n2; n2=((N2)ii)&0xF;
    if (!n2)
      ERR2("Error: GetAC[%u]: SS(0)",
      *r1->nn,n1);
    ii=GetVal(r1,(N1)n2);
    if (ii==-1l) return (-1l);
    if (n1==63)
      ERR3("Error: GetAC[%u]: SS(%u)",
      *r1->nn,n1,n2);
    ac[n1]=(I2)ii;
  }

  return (0);
}

/*==================================================================*/

I4 PutBit(tPutBit *r1,N1 b1)
{ if (!r1)
    ERR1("Error: PutBit: Param",-1l);
  r1->bb<<=1; r1->bb|=b1&1; ++r1->cnt;
  if (r1->cnt==8)
  { if (fwrite(&r1->bb,1,1,r1->f1)!=1)
      ERR1("Error: PutBit: Write/1",*r1->nn);
    ++*r1->nn;
    if (r1->bb==0xFFu)
    { r1->bb=0;
      if (fwrite(&r1->bb,1,1,r1->f1)!=1)
        ERR1("Error: PutBit: Write/2",*r1->nn);
      ++*r1->nn;
    }
    r1->bb=0; r1->cnt=0;
  }
  return (0);
}

I4 PutVal(tPutBit *r1,N2 v1,N1 l1)
{ N1 n1,n2; v1<<=16-l1;
  if (l1>16)
    ERR1("Error: PutVal: Param",-1l);
  for (n1=0;n1<l1;++n1)
  { n2=(N1)(v1>>15); v1<<=1;
    if (PutBit(r1,n2)==-1l)
      return (-1l);
  }
  return (0);
}

I4 Encode(tPutBit *r1,tHtab *h1,N4 d1)
{ N1 i1,n1;
  if (!h1)
    ERR1("Error: Encode: Param",-1l);
  n1=(N1)(d1>>16); i1=h1->ref[n1];
  if (PutVal(r1,h1->hufcod[i1],h1->hufsiz[i1])==-1l)
    return (-1l);
  if (PutVal(r1,(N2)d1,n1&0xF)==-1l)
    return (-1l);
  return (0);
}

N1 GetSS(I2 *vv)
{ N1 ss=0; I2 v1;
  if (*vv>=0)
  { v1=*vv;
    while (v1!=0)
    { ++ss; v1>>=1; }
  } else
  { v1=--*vv;
    while (v1!=-1)
    { ++ss; v1>>=1; }
  }
  return (ss);
}

#define mB1    h->b1
#define mB2    h->b2
#define mI1    h->i1
#define mN1    h->n1
#define mV1    h->v1
#define mD1    h->d1
I4 Comp1(tHuf *h)
{ N1 ss; I2 v1;
  if (mI1&63)
  { if (*mB1)
    { for (;mN1>=16;mN1-=16)
        *(mB2++)=BUFVAL(0xF0,0);
      v1=(I2)*mB1; ss=GetSS(&v1);
      *(mB2++)=BUFVAL(RRSS(mN1,ss),v1);
      mN1=0;
    } else ++mN1;
  } else
  { if (mN1)
    { *(mB2++)=0; mN1=0; }
    v1=((I2)*mB1)-mD1;
    mD1=(I2)*mB1;
    ss=GetSS(&v1);
    *(mB2++)=BUFVAL2(1,RRSS(0,ss),v1);
  }
  ++mB1; ++mI1;
  return (0);
}

I4 Comp2(tHuf *h,N4 m1)
{ if (mN1)
  { *mB1=((mN1==1 && mV1)?(N2)mV1:0);
    --mN1; --mB2;
  } else
  if (mI1&63)
  { if (!*mB2)
    { mN1=63-(mI1&63);
      *mB1=0; mV1=0;
    } else
    if (*mB2==BUFVAL(0xF0,0))
    { if (mI1+16>m1)
        ERR1("Error: Hufman: Decomp/1",0ul);
      *mB1=0; mV1=0; mN1=15;
    } else
    { mN1=(N1)(*mB2>>20);
      if (mI1+mN1>=m1)
        ERR1("Error: Hufman: Decomp/2",0ul);
      mV1=(N2)*mB2;
      if (mV1<0) ++mV1;
      if (mN1) *mB1=0;
      else *mB1=(N2)mV1;
    }
  } else
  { mV1=(N2)*mB2;
    if (mV1<0) ++mV1;
    mD1=mD1+mV1;
    *mB1=(N2)mD1;
  }
  ++mB2; ++mB1; ++mI1;
  return (0);
}
#undef mB1
#undef mB2
#undef mI1
#undef mN1
#undef mV1
#undef mD1

/*==================================================================*/

I4 PrepItem(tItem *itm)
{ tItem *r1; N2 n1; I2 i1,i2;
  while (1)
  { for (i1=i2=-1,n1=0;n1<257;++n1)
    { if (!itm[n1].num) continue;
      if (i1==-1 || itm[n1].num<=itm[i1].num)
      { i2=i1; i1=n1; continue; }
      if (i2==-1 || itm[n1].num<=itm[i2].num)
      { i2=n1; continue; }
    }
    if (i2==-1) break;
    itm[i1].num+=itm[i2].num; itm[i2].num=0;
    for (r1=&itm[i1];r1->next;r1=r1->next)
      ++r1->len; ++r1->len;
    r1->next=&itm[i2];
    for (r1=r1->next;r1->next;r1=r1->next)
      ++r1->len; ++r1->len;
  }
  return (0);
}

I4 PrepLen1(tItem *itm,N1 *len)
{ N2 i1;
  for (i1=0;i1<257;++i1)
  { N1 v1=itm[i1].len;
    if (v1>32) ERR1("Error: Huffman: Len32",0ul);
    if (v1) ++len[v1-1];
  }
  return (0);
}

I4 PrepLen2(tItem *itm,N1 *len)
{ N2 n1,n2; I2 i1,i2;
  for (n1=31;n1>15;)
  { if (!len[n1]) { --n1; continue; }
    for (i1=i2=-1,n2=0;n2<257;++n2)
    { if (itm[n2].len==n1+1)
      { i2=i1; i1=n2;
        if (i2!=-1) break;
      }
    }
    if (i2==-1)
      ERR1("Error: Huffman: Adjust/1",0ul);
    --itm[i1].len;
    len[n1]-=2; ++len[n1-1];
    for (n2=n1-2;1;--n2)
      if (len[n2]) break;
    for (i1=0;i1<257;++i1)
      if (itm[i1].len==n2+1) break;
    if (i1==257)
      ERR1("Error: Huffman: Adjust/2",0ul);
    ++itm[i1].len;
    itm[i2].len=itm[i1].len;
    --len[n2]; len[n2+1]+=2;
  }
  for (;!len[n1];--n1);
  --len[n1]; itm[256].len=0;
  return (0);
}

I4 PrepVal(tItem *itm,N1 *val,N2 n1)
{ N2 i1,i2,i3;
  for (i3=i1=0;i1<16;++i1)
  { for (i2=0;i2<256;++i2)
    { if (itm[i2].len==i1+1)
        val[i3++]=(N1)i2;
    }
  }
  if (i3!=n1)
    ERR1("Error: Huffman: HufVal",0ul);
  return (0);
}

I4 PrepTab(tHtab *htab,N4 nn)
{ N2 i1,i2,n1,n2;
  for (i1=i2=0,n1=0;n1<16;++n1,i2<<=1)
  { htab->hufidx[n1]=i1;
    htab->hufmin[n1]=i2;
    for (n2=0;n2<htab->len[n1];++n2,++i1,++i2)
    { htab->hufsiz[i1]=(N1)n1+1;
      htab->hufcod[i1]=(N2)i2;
    }
    htab->hufmax[n1]=i2-1;
    if (n2==0)
      htab->hufmin[n1]=htab->hufmax[n1]=-1;
  }
  if (i1!=htab->hufnum)
    ERR1("Error: Huffman: HufNum",nn);
  for (i1=0;i1<htab->hufnum;++i1)
    htab->ref[htab->val[i1]]=i1;
  return (0);
}


#endif
